using System;
using UnityEngine;

public class DemoOHJSClass
{
    private string logString = "";
    private OpenHarmonyJSClass m_ohJSClass = null;
    
    public string Test()
    {
        if (m_ohJSClass == null)
            m_ohJSClass = new OpenHarmonyJSClass("TSClass");
        Debug.Log($"InvokeStaticMethods");

        logString = string.Empty;
        TestStaticMethods();
        TestGetSet();

        return logString;
    }

    private void TestStaticMethods()
    {
        m_ohJSClass.CallStatic("FuncVoid", "Tuanjie & OpenHarmony", 9527);

        // ts 只有 number 类型, C# 则有 Byte/Int16/
        LogInvoke<sbyte>("TestType", 255);
        LogInvoke<byte>("TestType", 255);
        LogInvoke<int>("TestType", 10);
        LogInvoke<double>("TestType", 10);

        // 调用同一个接口，仅返回类型不一样
        LogInvoke<short>("Add", 32767, 1);
        // LogInvoke<ushort>("Add", 32767, 1); // 目前除了 byte 以外, 其它的类型都不允许有 unsigned
        LogInvoke<int>("Add", 32767, 1);

        // 布尔类型返回值
        LogInvoke<bool>("IsGreater", 32767, 1);

        // 字符串拼接
        LogInvoke<string>("StringConcatInJS", "AAA-str1", "BBB-str2");

        // C# 传递 array 到 ArkTS 并原样返回
        string[] strArray = new[] { "AAA", "BBB", "CCC" };
        int[] intArray = new[] { 111, 222, 333 };
        LogInvoke<Array>("ArrayFromCSharp", strArray, null);
        LogInvoke<Array>("ArrayFromCSharp", intArray, null);
    }

    private void TestGetSet()
    {
        LogGet<int>("mVal");
        LogGet<int>("GetNonExistsField"); // 会返回 0
        LogGet<string>("GetNonExistsField"); // 会返回 ""
        LogSet("mVal", 10);
        LogGet<int>("mVal");
        
        LogSet("SetNonExistsField", 10); // 会添加新的属性
        LogGet<int>("SetNonExistsField");

        LogGet<string>("mStrVal");
        LogSet("mStrVal", "string field value from C#");
        LogGet<string>("mStrVal");
        
        LogGet<Array>("mStringArray");
        LogSet("mStringArray", new string[]{"111", "222", "333"});
        LogGet<Array>("mStringArray");
    }

    private void LogInvoke<ReturnType>(string methodName, params object[] args)
    {
        var result = m_ohJSClass.CallStatic<ReturnType>(methodName, args);
        Log($"{methodName}<{typeof(ReturnType).Name}>({ArgsToString(args)})={ReturnToString(result)}");
    }

    private ReturnType LogGet<ReturnType>(string fieldName)
    {
        var result = m_ohJSClass.GetStatic<ReturnType>(fieldName);
        Log($"GetStatic<{typeof(ReturnType).Name}>(\"{fieldName}\")={ReturnToString(result)}");
        return result;
    }

    private void LogSet<FieldType>(string fieldName, FieldType val)
    {
        var result = m_ohJSClass.SetStatic(fieldName, val);
        Log($"SetStatic<{typeof(FieldType).Name}>(\"{fieldName}\", {ArgsToString(val)}), return={ReturnToString(result)}");
    }

    private string ArgsToString(params object[] args)
    {
        if (args == null || args.Length == 0)
            return "";
        
        var ret = $"{args[0]}";
        for (int i = 1; i < args.Length; i++)
        {
            ret += $", {args[i]}";
        }

        return ret;
    }

    private string ReturnToString(object obj)
    {
        if (obj.GetType().IsArray)
        {
            return ArrayToString(obj as Array);
        }

        return obj.ToString();
    }

    private string ArrayToString(Array array)
    {
        string log = array.Length + ":[";
        for (int i = 0; i < array.Length; i++)
        {
            if (i == 0)
                log += array.GetValue(i);
            else
                log += ", " + array.GetValue(i);
        }

        log += "]";
        return log;
    }

    private void Log(string log)
    {
        Debug.Log(log);
        logString += log.Replace('\0', ' ') + "\n";
        // mText.text = logString;
    }
}
